package ru.ifmo.ctddev.larionov.task9;

import java.io.*;
import java.net.*;
import java.util.Random;
import java.util.concurrent.*;

public class HelloUDPServer {

	private static int port;
	private static java.util.Random rand = new Random();
	private static Executor ex = new Executor() {
		@Override
		public void execute(Runnable command) {
			new Thread(command).start();
		}
	};

	public static void main(String[] args) {
		if (args.length < 1) {
			System.err.println("Argument missed!");
			return;
		}
		port = Integer.parseInt(args[0]);
		try {
			DatagramSocket dSocket = new DatagramSocket(port);
			int length = 100;
			DatagramPacket dPacket = new DatagramPacket(new byte[length],
					length);

			while (!Thread.currentThread().isInterrupted()) {
				try {
					dSocket.receive(dPacket);
					Runner r = new Runner(dPacket.getAddress(),
							dPacket.getData()[0] * 1000 + dPacket.getData()[1]
									* 10 + dPacket.getData()[2]);
					ex.execute(r);
				} catch (IOException e) {
					System.err.println("I/O error!");
				}
			}
		} catch (SocketException e) {
			System.err.println("Error with creating server!");
		}
	}

	private static class Runner implements Runnable {

		private InetAddress clientIAddress;
		private int clientPort;
		private static final Semaphore sem = new Semaphore(10);

		private Runner(InetAddress address, int clientPort) {
			this.clientIAddress = address;
			this.clientPort = clientPort;
		}

		@Override
		public void run() {
			try {
				sem.acquire();
				int port = rand.nextInt(55000) + 10000;
				DatagramSocket out = new DatagramSocket();
				out.connect(clientIAddress, clientPort);
				DatagramSocket in = new DatagramSocket(port);
				byte[] buf = new byte[100];
				buf[0] = (byte) (port / 1000);
				buf[1] = (byte) ((port % 1000) / 10);
				buf[2] = (byte) (port % 10);
				DatagramPacket dPacket = new DatagramPacket(buf, 3);
				out.send(dPacket);
				dPacket = new DatagramPacket(buf, 100);
				String s = new String();
				do {
					in.receive(dPacket);
					s = toString(dPacket.getData(), dPacket.getLength());
					if (!s.equals("end")) {
						s = "Hello, " + s;
						buf = s.getBytes();
						dPacket = new DatagramPacket(buf, buf.length);
						out.send(dPacket);
					}
				} while (!s.equals("end"));
			} catch (UnknownHostException e) {
				System.err.print("Cannot connect to ");
				for (int i = 0; i < clientIAddress.getAddress().length; ++i) {
					System.err.print(clientIAddress.getAddress()[i] + ".");
				}
				System.err.println();
			} catch (SocketException e) {
				System.err.println("Cannot create socket!");
			} catch (IOException e) {
				System.err.print("Cannot send to ");
				for (int i = 0; i < clientIAddress.getAddress().length; ++i) {
					System.err.print(clientIAddress.getAddress()[i] + ".");
				}
				System.err.println();
			} catch (InterruptedException e) {

			} finally {
				sem.release();
			}
		}

		private String toString(byte[] to, int length) {
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < length; ++i) {
				sb.append(to);
			}
			return sb.toString();
		}
	}
}
